經過兩天,開始看得懂/a{3,}?/i是什麼意思了。
這是一段隨意從網路上抓下來的Regexp。
寫得很嚴謹,e-mail網址的狀況都有設想到。
/^(|(([A-Za-z0-9]+_+)|([A-Za-z0-9]+\-+)|([A-Za-z0-9]+\.+)|([A-Za-z0-9]+\++))*[A-Za-z0-9]+@((\w+\-+)|(\w+\.))*\w{1,63}\.[a-zA-Z]{2,6})$/i
但在某些狀況下與這段是一樣的意思。
/^.+@.+$/
例如:
2.7.3 :020 > reg = /^(|(([A-Za-z0-9]+_+)|([A-Za-z0-9]+\-+)|([A-Za-z0-9]+\.+)|([A-Za-z0-9]+\++))*[A-Za-z0-9]+@((\w+\-+)|(\w+\.))*\w{1,63}\.[a-zA-Z]{2,6})$/i
2.7.3 :022 > mail = "A123__DD.dsf@gmail.com.taipei"
=> "A123__DD.dsf@gmail.com.taipei"
2.7.3 :023 > mail.match?(reg)
=> true
2.7.3 :024 > reg = /^.+@.+$/
=> /^.+@.+$/
2.7.3 :025 > mail = "A123__DD.dsf@gmail.com.taipei"
=> "A123__DD.dsf@gmail.com.taipei"
2.7.3 :026 > mail.match?(reg)
=> true
/^.+@.+$/這樣也過了!?先不論夠不夠嚴謹(因為如果我這樣寫連@@@這樣也能過),重點在於再嚴謹的表達式也要搭配正確的方法使用,如果沒有正確的方法,資料庫內也是只會出現一堆奇奇怪怪的mail,當然email的涵蓋範圍很大,各種形式的mail都有可能出現,去驗證e-mail到底正不正確,不如花時間去查這mail註冊過沒或是否uniq,或是假設mail不正確時,怎麼讓註冊不通過或讓用戶修改。
正規表達式用在檢測資料內有無特定資料,會比去規定用戶輸入正不正確時輕鬆,例如密碼要大小寫英文,不可以11111或123123這樣。
結論是Regexp不適合驗證email??!!
/./:點代表任何字元包含符號,但只有m模式下可匹配\n。
/abc/: 這樣等於要匹配有"abc"的部分。
/[abc]/: 這樣等於a or b or c。另外特殊字元被[]包住失去效果,成為單純符號。
2.7.3 :055 > /[$%]/.match("ac%$%")
=> #<MatchData "%">
2.7.3 :056 > "ac%$%".scan(/[$%]/)
=> ["%", "$", "%"]
/[^abc]/:這樣等於不要a or b or c。
2.7.3 :029 > "applebc".scan(/[^abc]/)
=> ["p", "p", "l", "e"]
/[a-z]/、/[A-Z]/: Any single character in the range。/[0-9]/: Any single number in the range。突然不會講中文...
\w:英文、數字與底線。\W:非英文、數字與底線。
2.7.3 :068 > /\w*/.match("apple")
=> #<MatchData "apple">
2.7.3 :069 > /\w/.match("apple")
=> #<MatchData "a">
\d:數字。\D:非數字。
\s:空白字元,包括空白、定位、換行、換頁。 它們 ====> ( \t\r\n\f\v)\S:非空白字元。
2.7.3 :094 > "You are a\ngood boy".scan(/(\s)/)
=> [[" "], [" "], ["\n"], [" "]]
2.7.3 :095 > "You are a\ngood boy".scan(/(\S)/)
=> [["Y"], ["o"], ["u"], ["a"], ["r"], ["e"], ["a"], ["g"], ["o"], ["o"], ["d"], ["b"], ["o"], ["y"]]
(?=regexp):確保後面的資料符合regexp。
2.7.3 :109 > /\w*+@(?=(gmail.com))/.match?("apple@hotmail.com")
=> false
2.7.3 :110 > /\w*+@(?=(gmail.com))/.match?("apple@gmail.com")
=> true
(?!regexp):確保後面的資料不符合regexp。
2.7.3 :111 > /\w*+@(?!(gmail.com))/.match?("apple@gmail.com")
=> false
(?<=regexp):確保前面的資料符合regexp。
2.7.3 :120 > /\d*(?<=0978)/.match("0978123111")
=> #<MatchData "0978">
2.7.3 :121 > /\d*(?<=0978)/.match?("0978123111")
=> true
2.7.3 :122 > /\d*(?<=0978)/.match?("0968123111")
=> false
(?<!regexp):確保前面的資料不符合regexp。
請多愛用令人尊敬且有愛的大神製作的Rubular:https://rubular.com/
def taiwan_mobile_number(nums)
reg = /\A((\+8869\d{2})|(09\d{2}))+((\d{6})|(\-+\d{3}){2}|(\s+\d{3}){2})\z/
nums.match?(reg)
end
puts taiwan_mobile_number("0954 666 666") #=> true
puts taiwan_mobile_number("0905-999-999") #=> true
puts taiwan_mobile_number("0905999888") #=> true
puts taiwan_mobile_number("+886913-333-333") #=> true
puts taiwan_mobile_number("+886913555666") #=> true
這題其實非常簡單,利用已經有的確定實例,來拼湊出Regexp。
我把+8869..與09..為第一區塊,也可以把+886跟0就當第一區塊。-...-...與\s...\s...當第二區塊,因為有-後面就不該有\s,所以直接都重複兩次。
當然一定有更漂亮寫法,我只是依照資料以及需求來寫。
Regexp。先不管其中是不是有更好的寫法。
/^(|(([A-Za-z0-9]+_+)|([A-Za-z0-9]+\-+)|([A-Za-z0-9]+\.+)|([A-Za-z0-9]+\++))*[A-Za-z0-9]+@((\w+\-+)|(\w+\.))*\w{1,63}\.[a-zA-Z]{2,6})$/i
第一個區塊。
(|(([A-Za-z0-9]+_+)|([A-Za-z0-9]+\-+)|([A-Za-z0-9]+\.+)|([A-Za-z0-9]+\++))*
[A-Za-Z0_9]+_+ : 大小寫英文與數字組合,加1或多個_,_沒有特殊意思,不需反斜線。
[A-Za-z0-9]+-+ : 大小寫英文與數字組合,加1或多個-,-需要反斜線。
[A-Za-z0-9]+.+ : 大小寫英文與數字組合,指定加1或多個.,\.代表要真正的.。
[A-Za-z0-9]+++ : 大小寫英文與數字組合,加1或多個+。
這四個可能的組合會出現0或多次,所以有一個*在()外。
第二區塊。
[A-Za-z0-9]+ #大小寫英文與數字組合出現1或多次。
這個蠻重要的@前面不可以有.、_、@這些符號。
第三區塊@,代表一定會有一個@。
第四區塊。@後面。
((\w+\-+)|(\w+\.))*
(\w+-+) : 任意非符號包含_字元加1或多個-。
(\w+.) : 任意非符號包含_,可以加真正的.。
以上組合可以出現0或多次所以()*。
第五區塊。
\w{1,63}\.[a-zA-Z]{2,6}
任意字元最少1個最多63個,一定有一個.,接2~6個大小寫英文字母。
雖然這邊似乎怪怪的,e-mail有可能會有複數/(\.[a-zA-Z])*/,不過沒關係,目的在認識別人寫的Regexp。
雖然我把正確表達式用三天分享很混,希望有機會能讓自己再次遇到Regexp不會再那麼陌生。
今天的leetcode10. Regular Expression Matching
題目連結:https://leetcode.com/problems/regular-expression-matching/
題目重點:p是一個實體,將實體變成Regexp,記得用#{}。
# @param {String} s
# @param {String} p
# @return {Boolean}
def is_match(s, p)
reg = /(#{p})/
s.match(reg)
s == $1
# s.match(/(#{p})/)
# s == $1
end
2.7.3 :039 > p = "a"
=> "a"
2.7.3 :040 > reg = /(#{p})/
=> /(a)/
2.7.3 :041 > s = "aa"
=> "aa"
2.7.3 :042 > s.match(reg)
=> #<MatchData "a" 1:"a">
2.7.3 :043 > s == $1
=> false
非常Easy的一題對吧,但這題其實被leetcode分類為Hard喔。
當熟悉表達式這些天書符號後,可以再多看看Regexp裡面的一些方法,對於leetcode的一些對字串檢查或替換的問題,也是比上面花不了多幾個字就解決了。